#region Using References

using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;

#endregion

namespace Beaker
{
	public static class EnumerableExtensions
	{
		/// <summary> 
		/// Caches the specified source but used deferred execution. 
		/// The first time the source is enumerated a cache of the items is created. 
		/// Subsequent calls to enumerate the source will use the cache. 
		/// </summary> 
		/// <typeparam name="TSource">The type of the source.</typeparam> 
		/// <param name="source">The source.</param> 
		/// <returns></returns> 
		public static IEnumerable<TSource> Buffer<TSource>( this IEnumerable<TSource> source )
		{
			return new CacheIterator<TSource>( source );
		}

		/// <summary> 
		///  
		/// </summary> 
		/// <typeparam name="TSource">The type of the source.</typeparam> 
		private class CacheIterator<TSource> : IEnumerable<TSource>
		{
			private readonly IEnumerable<TSource> _source;
			private readonly int _initialThreadId;
			private List<TSource> _cache;

			/// <summary> 
			/// Initializes a new instance of the <see cref="CacheIterator&lt;TSource&gt;"/> class. 
			/// </summary> 
			/// <param name="source">The source.</param> 
			[DebuggerHidden]
			public CacheIterator( IEnumerable<TSource> source )
			{
				_source = source;
				_initialThreadId = Thread.CurrentThread.ManagedThreadId;
			}

			#region IEnumerable<T> Members

			/// <summary> 
			/// Gets the enumerator. 
			/// </summary> 
			/// <returns></returns> 
			[DebuggerHidden]
			public IEnumerator<TSource> GetEnumerator()
			{
				if( Thread.CurrentThread.ManagedThreadId == _initialThreadId )
				{
					if( _cache == null )
						_cache = _source.ToList();

					return _cache.GetEnumerator();
				}
				else
				{
					var enumerator = new CacheIterator<TSource>( _source );
					return enumerator.GetEnumerator();
				}
			}

			#endregion

			#region IEnumerable Members

			/// <summary> 
			/// Returns an enumerator that iterates through a collection. 
			/// </summary> 
			/// <returns> 
			/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection. 
			/// </returns> 
			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}

			#endregion
		}
	}
}